1   /*
2    * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.
8    *
9    * This code is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12   * version 2 for more details (a copy is included in the LICENSE file that
13   * accompanied this code).
14   *
15   * You should have received a copy of the GNU General Public License version
16   * 2 along with this work; if not, write to the Free Software Foundation,
17   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18   *
19   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20   * or visit www.oracle.com if you need additional information or have any
21   * questions.
22   */
23  
24  /*
25   *
26   * @test
27   * @bug 4533872 4915683 4922962 4985217 5017280 6242664 6588260
28   * @summary Unit tests for supplementary character support (JSR-204)
29   */
30  
31  public class Supplementary {
32  
33      public static void main(String[] args) {
34          test1();        // Test for codePointAt(int index)
35          test2();        // Test for codePointBefore(int index)
36          test3();        // Test for indexOf(int ch)
37          test4();        // Test for indexOf(int ch, int fromIndex)
38          test5();        // Test for lastIndexOf(int ch)
39          test6();        // Test for lastIndexOf(int ch, int fromIndex)
40          test7();        // Test for String(int[] codePoint, int offset, int count)
41          test8();        // Test for codePointCount(int beginIndex, int endIndex)
42          test9();        // Test for offsetByCodePoints(int index, int offset)
43          test10();       // Test for offsetByCodePoints(int index, int offset)
44                          // To verify the fix for 6242664
45      }
46  
47      /* Text strings which are used as input data.
48       * The comment above each text string means the index of each 16-bit char
49       * for convenience.
50       */
51      static final String[] input = {
52        /*                               111     1     111111     22222
53           0123     4     5678     9     012     3     456789     01234 */
54          "abc\uD800\uDC00def\uD800\uD800ab\uD800\uDC00cdefa\uDC00bcdef",
55        /*                          1     1111     1111     1     222
56           0     12345     6789     0     1234     5678     9     012     */
57          "\uD800defg\uD800hij\uD800\uDC00klm\uDC00nop\uDC00\uD800rt\uDC00",
58        /*                          11     1     1111     1     112     222
59           0     12345     6     78901     2     3456     7     890     123     */
60          "\uDC00abcd\uDBFF\uDFFFefgh\uD800\uDC009ik\uDC00\uDC00lm\uDC00no\uD800",
61        /*                                    111     111111     1 22     2
62           0     1     2345     678     9     012     345678     9 01     2     */
63          "\uD800\uDC00!#$\uD800%&\uD800\uDC00;+\uDC00<>;=^\uDC00\\@\uD800\uDC00",
64  
65          // includes an undefined supplementary character in Unicode 4.0.0
66        /*                                    1     11     1     1111     1
67           0     1     2345     6     789     0     12     3     4567     8     */
68          "\uDB40\uDE00abc\uDE01\uDB40de\uDB40\uDE02f\uDB40\uDE03ghi\uDB40\uDE02",
69  
70          // all supplementary characters
71        /*                                                             1     1
72           0     1     2     3     4     5     6     7     8     9     0     1     */
73          "\uD800\uDC00\uD800\uDC01\uD800\uDC02\uD800\uDC03\uD800\uDC04\uD800\uDC05"+
74        /* 1     1     1     1     1     1     1     1     2     2     2     2
75           2     3     4     5     6     7     8     9     0     1     2     3     */
76          "\uD800\uDC06\uD800\uDC07\uD800\uDC08\uD800\uDC08\uD800\uDC09\uD800\uDC0A"+
77        /* 2     2     2     2     2     2     3     3     3     3     3     3
78           4     5     6     7     8     9     0     1     2     3     4     5     */
79          "\uD800\uDC0B\uD800\uDC0C\uD800\uDC0D\uD800\uDC0A\uD800\uDC0F\uD800\uDC10"
80      };
81  
82  
83      /* Expected results for:
84       *     test1(): for codePointAt()
85       *
86       * Each character in each array is the golden data for each text string
87       * in the above input data. For example, the first data in each array is
88       * for the first input string.
89       */
90      static final int[][] golden1 = {
91          {'a',    0xD800,  0xDC00, 0x10000, 0xE0200, 0x10000},// codePointAt(0)
92          {0xD800, 0x10000, 'g',    0xDC00,  0xE0202, 0xDC04}, // codePointAt(9)
93          {'f',    0xDC00,  0xD800, 0xDC00,  0xDE02,  0xDC10}, // codePointAt(length-1)
94          {'f',    'p',     0xDC00, '^',     0xE0202, 0xDC08}, // codePointAt() for a substring
95      };
96  
97      /*
98       * Test for codePointAt(int index) method
99       */
100     static void test1() {
101 
102         for (int i = 0; i < input.length; i++) {
103             String s = input[i];
104 
105             /*
106              * Normal case
107              */
108             testCodePoint(At, s, 0, golden1[0][i]);
109             testCodePoint(At, s, 9, golden1[1][i]);
110             testCodePoint(At, s, s.length()-1, golden1[2][i]);
111             testCodePoint(At, s.substring(17), 0, golden1[3][i]);
112 
113             /*
114              * Abnormal case - verify that an exception is thrown.
115              */
116             testCodePoint(At, s, -1);
117             testCodePoint(At, s, s.length());
118         }
119     }
120 
121 
122     /* Expected results for:
123      *     test2(): for codePointBefore()
124      *
125      * Each character in each array is the golden data for each text string
126      * in the above input data. For example, the first data in each array is
127      * for the first input string.
128      */
129     static final int[][] golden2 = {
130         {'a',    0xD800, 0xDC00,  0xD800,  0xDB40,  0xD800}, // codePointBefore(1)
131         {0xD800, 'l',    0x10000, 0xDC00,  0xDB40,  0xD800}, // codePointBefore(13)
132         {'f',    0xDC00, 0xD800,  0x10000, 0xE0202, 0x10010},// codePointBefore(length)
133         {'b',    'd',    'a',     0xDC00,  0xDE00,  0xDC00}, // codePointBefore() for a substring
134     };
135 
136     /*
137      * Test for codePointBefore(int index) method
138      */
139     static void test2() {
140 
141         for (int i = 0; i < input.length; i++) {
142             String s = input[i];
143 
144             /*
145              * Normal case
146              */
147             testCodePoint(Before, s, 1, golden2[0][i]);
148             testCodePoint(Before, s, 13, golden2[1][i]);
149             testCodePoint(Before, s, s.length(), golden2[2][i]);
150             testCodePoint(Before, s.substring(1), 1, golden2[3][i]);
151 
152             /*
153              * Abnormal case - verify that an exception is thrown.
154              */
155             testCodePoint(Before, s, 0);
156             testCodePoint(Before, s, s.length()+1);
157         }
158     }
159 
160 
161     /* Expected results for:
162      *     test3(): for indexOf(int ch)
163      *     test4(): for indexOf(int ch, int fromIndex)
164      *     test5(): for lastIndexOf(int ch)
165      *     test6(): for lastIndexOf(int ch, int fromIndex)
166      *
167      * Unlike golden1 and golden2, golden3[m][] is the golden data for text
168      * string in input[m].
169      *
170      * The meaning of each element in golden3[][n]
171      *   golden3[][0]: character which is searched.
172      *   golden3[][2]: the golden data for indexOf(int ch)
173      *   From golden3[][2] to golden3[][n-1]:
174      *       the golden data for indexOf(int ch, int fromIndex)
175      *   The golden3[][n-2]: the golden data for lastIndexOf(int ch)
176      *   From golden3[][1] to golden3[][n-2]:
177      *       the golden data for lastIndexOf(int ch, int fromIndex)
178      *
179      *   In other words, the data format is
180      *     { ch, -1, index1, index2, ..., -1}
181      *   where index1, index2, ... are all indices of the ch occurrences.
182      */
183     static final int[][] golden3 = {
184       /* ch       indices */
185         {'b',     -1,  1, 11, 20,  -1},
186         {0xD800,  -1,  0,  5,  9,  19, -1},
187         {0xDC00,  -1,  0, 12, 16,  17, 20, -1},
188         {0x10000, -1,  0,  8, 21,  -1},
189         {0xE0202, -1,  9, 17, -1},
190         {0x1000A, -1, 22, 30, -1}
191     };
192 
193     /*
194      * Test for indexOf(int ch) method
195      */
196     static void test3() {
197 
198         for (int i = 0; i < input.length; i++) {
199             String s = input[i];
200 
201             /*
202              * Normal case
203              */
204             testIndexOf(s, golden3[i][0], golden3[i][2]);
205 
206             /*
207              * Abnormal case - char which isn't included in the string.
208              */
209             testIndexOf(s, 'Z', -1);
210             testIndexOf(s, 0xDB98, -1);
211             testIndexOf(s, 0xDE76, -1);
212             testIndexOf(s, 0x12345, -1);
213             testIndexOf(s, -1, -1);
214             testIndexOf(s, 0x110000, -1);
215         }
216     }
217 
218     /*
219      * Test for indexOf(int ch, int fromIndex) method
220      */
221     static void test4() {
222 
223         for (int i = 0; i < input.length; i++) {
224             String s = input[i];
225             int ch = golden3[i][0];
226 
227             /*
228              * Normal case
229              */
230             int fromIndex = 0;
231             for (int j = 2; j < golden3[i].length; j++) {
232                 fromIndex = testIndexOf(s, fromIndex, ch,
233                                         golden3[i][j]) + 1;
234             }
235 
236             /*
237              * Abnormal case1 - char is included in the string but fromIndex
238              *                  is incorrect.
239              */
240             testIndexOf(s, -1, ch, golden3[i][2]);
241             testIndexOf(s, s.length(), ch,
242                         golden3[i][golden3[i].length-1]);
243 
244             /*
245              * Abnormal case2 - char which isn't included in the string.
246              */
247             testIndexOf(s, 0, 'Z', -1);
248             testIndexOf(s, 0, 0xDB98, -1);
249             testIndexOf(s, 0, 0xDE76, -1);
250             testIndexOf(s, 0, 0x12345, -1);
251             testIndexOf(s, 0, -1, -1);
252             testIndexOf(s, 0, 0x110000, -1);
253         }
254     }
255 
256     /*
257      * Test for lastIndexOf(int ch) method
258      */
259     static void test5() {
260 
261         for (int i = 0; i < input.length; i++) {
262             String s = input[i];
263 
264             /*
265              * Normal case
266              */
267             testLastIndexOf(s, golden3[i][0],
268                         golden3[i][golden3[i].length-2]);
269 
270             /*
271              * Abnormal case - char which isn't included in the string.
272              */
273             testLastIndexOf(s, 'Z', -1);
274             testLastIndexOf(s, 0xDB98, -1);
275             testLastIndexOf(s, 0xDE76, -1);
276             testLastIndexOf(s, 0x12345, -1);
277             testLastIndexOf(s, -1, -1);
278             testLastIndexOf(s, 0x110000, -1);
279         }
280     }
281 
282     /*
283      * Test for lastIndexOf(int ch, int fromIndex) method
284      */
285     static void test6() {
286 
287         for (int i = 0; i < input.length; i++) {
288             String s = input[i];
289             int ch = golden3[i][0];
290             int len = s.length();
291 
292             /*
293              * Normal case
294              */
295             int fromIndex = len - 1;
296             for (int j = golden3[i].length - 2; j > 0; j--) {
297                 fromIndex = testLastIndexOf(s, fromIndex, ch,
298                                         golden3[i][j]) - 1;
299             }
300 
301             /*
302              * Abnormal case1 - char is included in the string but fromIndex
303              *                  is incorrect.
304              */
305             testLastIndexOf(s, -1, ch, golden3[i][1]);
306             testLastIndexOf(s, len, ch, golden3[i][golden3[i].length-2]);
307 
308             /*
309              * Abnormal case2 - char which isn't included in the string.
310              */
311             testLastIndexOf(s, len, 'Z', -1);
312             testLastIndexOf(s, len, 0xDB98, -1);
313             testLastIndexOf(s, len, 0xDE76, -1);
314             testLastIndexOf(s, len, 0x12345, -1);
315             testLastIndexOf(s, len, -1, -1);
316             testLastIndexOf(s, len, 0x110000, -1);
317         }
318     }
319 
320     /**
321      * Test for String(int[] codePoint, int offset, int count).
322      */
323     static void test7() {
324         for (int i = 0; i < input.length; i++) {
325             String s = input[i];
326             int nCodePoints = 0;
327             int c;
328             for (int j = 0; j < s.length(); j += Character.charCount(c)) {
329                 c = s.codePointAt(j);
330                 nCodePoints++;
331             }
332             int[] codePoints = new int[nCodePoints];
333             int count = 0, mid = 0, offset = 0;
334             for (int j = 0; j < s.length(); j += Character.charCount(c)) {
335                 if (mid == 0 && j >= s.length()/2) {
336                     mid = j;
337                     offset = count;
338                 }
339                 c = s.codePointAt(j);
340                 codePoints[count++] = c;
341             }
342 
343             String cps = new String(codePoints, 0, count);
344             check(!s.equals(cps), "new String(int[]...) with input[" + i + "]");
345 
346             cps = new String(codePoints, 0, offset);
347             check(!s.substring(0, mid).equals(cps),
348                   "first half: new String(int[]...) with input[" + i + "]");
349 
350             cps = new String(codePoints, offset, count - offset);
351             check(!s.substring(mid).equals(cps),
352                   "second half: new String(int[]...) with input[" + i + "]");
353 
354             // test exceptions
355             testNewString(null, 0, count, NullPointerException.class);
356             testNewString(codePoints, -1, count, IndexOutOfBoundsException.class);
357             testNewString(codePoints, 0, count+1, IndexOutOfBoundsException.class);
358             testNewString(codePoints, offset, count, IndexOutOfBoundsException.class);
359             testNewString(codePoints, offset, -1, IndexOutOfBoundsException.class);
360             testNewString(codePoints, count, 1, IndexOutOfBoundsException.class);
361             codePoints[offset] = -1;
362             testNewString(codePoints, 0, count, IllegalArgumentException.class);
363             codePoints[offset] = Character.MAX_CODE_POINT+1;
364             testNewString(codePoints, 0, count, IllegalArgumentException.class);
365         }
366 
367         {
368             // 6588260: (str) ArrayIndexOutOfBoundsException when trying
369             // to create a String from codePoints
370             //int[] x = new int[Character.MAX_CODE_POINT+1];
371             int[] x = new int[Character.MAX_CODE_POINT];
372             for (int i = 0; i < x.length; i++)
373                 if (i != 0xdbff) // For round-trip safety
374                     x[i] = i;
375             final String s = new String(x, 0, x.length);
376             check(s.codePointCount(0, s.length()) != x.length,
377                   "s.codePointCount(0, s.length()) != x.length");
378             check(s.length() <= x.length,
379                   "s.length() <= x.length");
380             for (int i = 0, j = 0; i < x.length; i++) {
381                 int c = s.codePointAt(j);
382                 check(c != x[i], "c != x[i]");
383                 j += Character.charCount(c);
384             }
385         }
386     }
387 
388     /**
389      * Test codePointCount(int, int)
390      *
391      * This test case assumes that
392      * Character.codePointCount(CharSequence, int, int) works
393      * correctly.
394      */
395     static void test8() {
396         for (int i = 0; i < input.length; i++) {
397             String str = input[i];
398             int length = str.length();
399             for (int j = 0; j <= length; j++) {
400                 int result = str.codePointCount(j, length);
401                 int expected = Character.codePointCount(str, j, length);
402                 check(result != expected, "codePointCount(input["+i+"], "+j+", "+length+")",
403                       result, expected);
404                 // Create a substring of the text range. It shares the
405                 // underlying char[] of the String str.
406                 String substr = str.substring(j, length);
407                 result = substr.codePointCount(0, substr.length());
408                 check(result != expected, "substring:codePointCount(input["+i+"], "+j+", "+length+")",
409                       result, expected);
410             }
411             for (int j = length; j >= 0; j--) {
412                 int result = str.codePointCount(0, j);
413                 int expected = Character.codePointCount(str, 0, j);
414                 check(result != expected, "codePointCount(input["+i+"], 0, "+j+")",
415                       result, expected);
416                 String substr = str.substring(0, j);
417                 result = substr.codePointCount(0, substr.length());
418                 check(result != expected, "substring:codePointCount(input["+i+"], 0, "+j+")",
419                       result, expected);
420             }
421 
422             // test exceptions
423             testCodePointCount(null, 0, 0, NullPointerException.class);
424             testCodePointCount(str, -1, length, IndexOutOfBoundsException.class);
425             testCodePointCount(str, 0, length+1, IndexOutOfBoundsException.class);
426             testCodePointCount(str, length, length-1, IndexOutOfBoundsException.class);
427         }
428     }
429 
430     /**
431      * Test offsetByCodePoints(int, int)
432      *
433      * This test case assumes that
434      * Character.codePointCount(CharSequence, int, int) works
435      * correctly.
436      */
437     static void test9() {
438         for (int i = 0; i < input.length; i++) {
439             String str = input[i];
440             int length = str.length();
441             for (int j = 0; j <= length; j++) {
442                 int nCodePoints = Character.codePointCount(str, j, length);
443                 int result = str.offsetByCodePoints(j, nCodePoints);
444                 check(result != length,
445                       "offsetByCodePoints(input["+i+"], "+j+", "+nCodePoints+")",
446                       result, length);
447                 result = str.offsetByCodePoints(length, -nCodePoints);
448                 int expected = j;
449                 if (j > 0 && j < length) {
450                     int cp = str.codePointBefore(j+1);
451                     if (Character.isSupplementaryCodePoint(cp)) {
452                         expected--;
453                     }
454                 }
455                 check(result != expected,
456                       "offsetByCodePoints(input["+i+"], "+j+", "+(-nCodePoints)+")",
457                       result, expected);
458             }
459             for (int j = length; j >= 0; j--) {
460                 int nCodePoints = Character.codePointCount(str, 0, j);
461                 int result = str.offsetByCodePoints(0, nCodePoints);
462                 int expected = j;
463                 if (j > 0 && j < length) {
464                     int cp = str.codePointAt(j-1);
465                      if (Character.isSupplementaryCodePoint(cp)) {
466                         expected++;
467                     }
468                 }
469                 check(result != expected,
470                       "offsetByCodePoints(input["+i+"], 0, "+nCodePoints+")",
471                       result, expected);
472                 result = str.offsetByCodePoints(j, -nCodePoints);
473                 check(result != 0,
474                       "offsetByCodePoints(input["+i+"], "+j+", "+(-nCodePoints)+")",
475                       result, 0);
476             }
477 
478             // test exceptions
479             testOffsetByCodePoints(null, 0, 0, NullPointerException.class);
480             testOffsetByCodePoints(str, -1, length, IndexOutOfBoundsException.class);
481             testOffsetByCodePoints(str, 0, length+1, IndexOutOfBoundsException.class);
482             testOffsetByCodePoints(str, 1, -2, IndexOutOfBoundsException.class);
483             testOffsetByCodePoints(str, length, length-1, IndexOutOfBoundsException.class);
484             testOffsetByCodePoints(str, length, -(length+1), IndexOutOfBoundsException.class);
485         }
486     }
487 
488     /**
489      * Test offsetByCodePoints(int, int) - to verify the fix for 6242664
490      *
491      * This test case assumes that
492      * Character.codePointCount(CharSequence, int, int) works
493      * correctly.
494      */
495     static void test10() {
496         String header = "H\uD800e\uDFFFa\uDBFF\uDC00der<";
497         for (int i = 0; i < input.length; i++) {
498             String wholeString = header + input[i];
499             String str = wholeString.substring(header.length());
500             int length = str.length();
501             for (int j = 0; j <= length; j++) {
502                 int nCodePoints = Character.codePointCount(str, j, length);
503                 int result = str.offsetByCodePoints(j, nCodePoints);
504                 check(result != length,
505                       "offsetByCodePoints(input["+i+"], "+j+", "+nCodePoints+")",
506                       result, length);
507                 result = str.offsetByCodePoints(length, -nCodePoints);
508                 int expected = j;
509                 if (j > 0 && j < length) {
510                     int cp = str.codePointBefore(j+1);
511                     if (Character.isSupplementaryCodePoint(cp)) {
512                         expected--;
513                     }
514                 }
515                 check(result != expected,
516                       "offsetByCodePoints(input["+i+"], "+j+", "+(-nCodePoints)+")",
517                       result, expected);
518             }
519             for (int j = length; j >= 0; j--) {
520                 int nCodePoints = Character.codePointCount(str, 0, j);
521                 int result = str.offsetByCodePoints(0, nCodePoints);
522                 int expected = j;
523                 if (j > 0 && j < length) {
524                     int cp = str.codePointAt(j-1);
525                      if (Character.isSupplementaryCodePoint(cp)) {
526                         expected++;
527                     }
528                 }
529                 check(result != expected,
530                       "offsetByCodePoints(input["+i+"], 0, "+nCodePoints+")",
531                       result, expected);
532                 result = str.offsetByCodePoints(j, -nCodePoints);
533                 check(result != 0,
534                       "offsetByCodePoints(input["+i+"], "+j+", "+(-nCodePoints)+")",
535                       result, 0);
536             }
537         }
538     }
539 
540 
541     static final boolean At = true, Before = false;
542     static final boolean FIRST = true, LAST = false;
543 
544     static void testCodePoint(boolean isAt, String s, int index, int expected) {
545         int c = isAt ? s.codePointAt(index) : s.codePointBefore(index);
546 
547         check(c != expected,
548               "codePoint" + (isAt ? "At" : "Before") + "(" + index + ") for <"
549               + s + ">", c, expected);
550     }
551 
552     static void testCodePoint(boolean isAt, String s, int index) {
553         boolean exceptionOccurred = false;
554 
555         try {
556             int c = isAt ? s.codePointAt(index) : s.codePointBefore(index);
557         }
558         catch (StringIndexOutOfBoundsException e) {
559             exceptionOccurred = true;
560         }
561         check(!exceptionOccurred,
562               "codePoint" + (isAt ? "At" : "Before") + "(" + index + ") for <"
563               + s + "> should throw StringIndexOutOfBoundsPointerException.");
564     }
565 
566     static void testIndexOf(String s, int c, int expected) {
567         testIndexOf2(s, c, expected);
568         if (s.indexOf(c) != -1) {
569             testIndexOf2(s + (char) c, c, expected);
570             if (Character.isSupplementaryCodePoint(c)) {
571                 char[] surrogates = Character.toChars(c);
572                 testIndexOf2(s + new String(surrogates), c, expected);
573                 testIndexOf2(s + surrogates[0], c, expected);
574                 testIndexOf2(s + surrogates[1], c, expected);
575                 testIndexOf2(new String(surrogates) + s, c, 0);
576                 testIndexOf2(surrogates[0] + s, c, expected + 1);
577                 testIndexOf2(surrogates[1] + s, c, expected + 1);
578             }
579         }
580     }
581 
582     static void testIndexOf2(String s, int c, int expected) {
583         int index = s.indexOf(c);
584 
585         check(index != expected,
586               "indexOf(" + toHexString(c) + ") for <" + s + ">",
587               index, expected);
588     }
589 
590     static void testLastIndexOf(String s, int c, int expected) {
591         testLastIndexOf2(s, c, expected);
592         if (s.lastIndexOf(c) != -1) {
593             testLastIndexOf2((char) c + s, c, expected + 1);
594             if (Character.isSupplementaryCodePoint(c)) {
595                 char[] surrogates = Character.toChars(c);
596                 testLastIndexOf2(s + new String(surrogates), c, s.length());
597                 testLastIndexOf2(s + surrogates[0], c, expected);
598                 testLastIndexOf2(s + surrogates[1], c, expected);
599                 testLastIndexOf2(new String(surrogates) + s, c, expected + 2);
600                 testLastIndexOf2(surrogates[0] + s, c, expected + 1);
601                 testLastIndexOf2(surrogates[1] + s, c, expected + 1);
602             }
603         }
604     }
605 
606     static void testLastIndexOf2(String s, int c, int expected) {
607         int index = s.lastIndexOf(c);
608 
609         check(index != expected,
610               "lastIndexOf(" + toHexString(c) + ") for <" + s + ">",
611               index, expected);
612     }
613 
614     static int testIndexOf(String s, int fromIndex, int c, int expected) {
615         int index = s.indexOf(c, fromIndex);
616 
617         check(index != expected,
618               "indexOf(" + toHexString(c) + ", "
619               + fromIndex + ") for <" + s + ">",
620               index, expected);
621 
622         return index;
623     }
624 
625     static int testLastIndexOf(String s, int fromIndex, int c, int expected) {
626         int index = s.lastIndexOf(c, fromIndex);
627 
628         check(index != expected,
629               "lastIndexOf(" + toHexString(c) + ", "
630               + fromIndex + ") for <" + s + ">",
631               index, expected);
632 
633         return index;
634     }
635 
636     static void testNewString(int[] codePoints, int offset, int count, Class expectedException) {
637         try {
638             String s = new String(codePoints, offset, count);
639         } catch (Exception e) {
640             if (expectedException.isInstance(e)) {
641                 return;
642             }
643             throw new RuntimeException("Error: Unexpected exception", e);
644         }
645         check(true, "new String(int[]...) didn't throw " + expectedException.getName());
646     }
647 
648     static void testCodePointCount(String str, int beginIndex, int endIndex,
649                                    Class expectedException) {
650         try {
651             int n = str.codePointCount(beginIndex, endIndex);
652         } catch (Exception e) {
653             if (expectedException.isInstance(e)) {
654                 return;
655             }
656             throw new RuntimeException("Error: Unexpected exception", e);
657         }
658         check(true, "codePointCount() didn't throw " + expectedException.getName());
659     }
660 
661     static void testOffsetByCodePoints(String str, int index, int offset,
662                                        Class expectedException) {
663         try {
664             int n = str.offsetByCodePoints(index, offset);
665         } catch (Exception e) {
666             if (expectedException.isInstance(e)) {
667                 return;
668             }
669             throw new RuntimeException("Error: Unexpected exception", e);
670         }
671         check(true, "offsetByCodePoints() didn't throw " + expectedException.getName());
672     }
673 
674     static void check(boolean err, String msg) {
675         if (err) {
676             throw new RuntimeException("Error: " + msg);
677         }
678     }
679 
680     static void check(boolean err, String s, int got, int expected) {
681         if (err) {
682             throw new RuntimeException("Error: " + s
683                                        + " returned an unexpected value. got "
684                                        + toHexString(got)
685                                        + ", expected "
686                                        + toHexString(expected));
687         }
688     }
689 
690     private static String toHexString(int c) {
691         return "0x" + Integer.toHexString(c);
692     }
693 }